/*--------------------------------------------------------------------------------------*\
**
** adv_whirlpool.cpp
**
** Heroes IV
** Copyright 2000, The 3DO Company
**
\*--------------------------------------------------------------------------------------*/

// kill the 255+ character identifier warning.  Templates tend to exceed that easily.
#include "precompiled.h"
#pragma warning( disable: 4786 )

#include "adv_whirlpool.h"

#include "adv_object_type.h"
#include "adventure_frame.h"
#include "adventure_map.h"
#include "adv_object_type.h"
#include "adv_actor_model.h"
#include "army.h"
#include "bitmap_group_cache.h"
#include "bound_handler.h"
#include "creature_type.h"
#include "hero.h"
#include "object_registration.h"
#include "random.h"
#include "simple_dialog.h"
#include "stationary_adventure_object.h"

// --------------------------------------------------------------------------
// Unnamed namespace
// --------------------------------------------------------------------------

namespace
{

	t_object_registration< t_adv_whirlpool > g_adv_whirlpool_registration( k_adv_object_whirlpool );

    struct t_creature_amount_pair
    {
        t_creature_type     m_creature_type;
        int                 m_amount;
    };
} // Unnamed namespace

t_adv_whirlpool::t_adv_whirlpool ( std::string const& model_name )
          : t_gateway_base( model_name )
{
}

void t_adv_whirlpool::activate_trigger( t_army* army, t_adv_map_point const& point, 
		                                t_direction direction, t_adventure_frame* frame )
{
    t_adv_whirlpool_vector		whirlpool_list = m_map->get_whirlpools( );
    t_adv_whirlpool_vector		possible_gateways;
    int                         selected_gateway = 0;
    int                         i;
	t_adventure_map_ptr			map = get_map();
	bool						found_whirlpool_with_space = false;

    for (i=0; i < whirlpool_list.size(); i++)
    {
	    if (this != whirlpool_list[i].get())
        {
			t_adv_whirlpool_ptr whirlpool = whirlpool_list[i];
			t_adv_map_point adjacent_space;

			// Prefer whirlpools with free spaces next to them
			bool has_space = whirlpool->find_adjacent_space( adjacent_space, *army );

			if ( !has_space && found_whirlpool_with_space )
				continue;

			if ( has_space && !found_whirlpool_with_space )
			{
				possible_gateways.clear();
				found_whirlpool_with_space = true;
			}

            // Create a list of possible gateways.
            possible_gateways.push_back( whirlpool );
        }
    }
 
	// No other gateways!
    if (possible_gateways.empty())
	{
		ok_dialog( get_text("denied"), true, get_text("name") );
        return;
	}


    // Pick a random one...
    selected_gateway = random( 0, ( possible_gateways.size() - 1 ) );

	/*
    ** Teleport army.
	** Do NOT allow trades through a whirlpool; would allow players to get
	** armies through whirlpools without paying cost
    */
    teleport_army ( *possible_gateways[ selected_gateway ], army, frame, false,
					get_text("initial"), 
					bound_handler( *this, &t_adv_whirlpool::cause_damage_to_army ) );
}

/*
** Cause damage to army.  Quantity of each type of creature
** goes down 10%.  Hero gets 10% wound.
*/
void t_adv_whirlpool::cause_damage_to_army(t_army* army_ptr)
{

	t_creature_array& creatures = army_ptr->get_creatures();
	std::vector<t_creature_amount_pair> creature_list;
	t_hero*     hero_ptr;
    int     i;
    int     j;
	bool    has_hero = false;

    /*
    ** Do damage to heroes, set creature list.
    */
	for (i = 0; i < t_creature_array::k_size; i++)
	{
		hero_ptr = creatures[i].get_hero();

        // Is it a hero?
        if (hero_ptr && !hero_ptr->is_dead() )
        {
            // Hero gets 10% damage, rounded up.
			// Don't actually kill them, though
			int current_hits = hero_ptr->get_hit_points() - hero_ptr->get_wounds();

	        int new_wounds = hero_ptr->get_wounds() + ((current_hits + 9) / 10);

			if ( new_wounds >= hero_ptr->get_hit_points() )
				new_wounds = hero_ptr->get_hit_points() - 1;

            hero_ptr->set_wounds( new_wounds );

			has_hero = true;

            continue;
        }
        
        // Creature in this slot?
	    t_creature const* creature_ptr = creatures[i].get_const_creature();
        if (!creature_ptr)
        {
            continue;
        }

        // Check if creature has already been added to the list.
	    t_creature_type const creature_type = creatures[i].get_creature_type();
	    int count = creatures[i].get_number();
        bool is_in_list = false;

        for (j = 0; j<creature_list.size(); j++)
        {
            // Creature is in list, add to quantity.
            if (creature_type == creature_list[j].m_creature_type)
            {
                creature_list[j].m_amount += count;

                is_in_list = true;
            }
        }

        // If creature is not in list, add to list.
        if (!is_in_list)
        {
            t_creature_amount_pair creature_info;

            creature_info.m_creature_type = creature_type;
            creature_info.m_amount = count;
            creature_list.push_back (creature_info);
        }
    }

    /*
    ** Now remove creatures.
    */
	bool has_surviving_creature = false;

    for (j = 0; j<creature_list.size(); j++)
    {
        // Remove 10%, rounded up.
        int amount_to_remove;
		
		if ( creature_list[j].m_amount > 1 )
			amount_to_remove = (creature_list[j].m_amount + 9) / 10;
		else
			amount_to_remove = 1;

		// Don't actually kill the entire army
		if ( amount_to_remove < creature_list[j].m_amount )
		{
			has_surviving_creature = true;
		}
		else
		{
			if ( !has_hero && !has_surviving_creature && j == creature_list.size() - 1 )
				amount_to_remove = creature_list[j].m_amount - 1;
		}


        i = 0;
	    while ((i < t_creature_array::k_size) && amount_to_remove)
    	{
            i++;
            int index = (i-1);

	        t_creature const* creature_ptr = creatures[index].get_const_creature();

            if (!creature_ptr)
                continue;

    	    if (creatures[index].get_creature_type() != creature_list[j].m_creature_type)
                continue;

            const int creature_amount = creatures[index].get_number();
            if (creature_amount <= amount_to_remove)
            {
                creatures.clear( index );
                amount_to_remove -= creature_amount;
            }
            else
            {
                creatures[index].remove( amount_to_remove );
                amount_to_remove = 0;
            }
        }
    }
}

void t_adv_whirlpool::destroy()
{
	m_map->remove_whirlpool( this );

	t_gateway_base::destroy();
}


void t_adv_whirlpool::place( t_adventure_map& map, t_adv_map_point const& point )
{
    t_gateway_base::place( map, point );
    
    // Add whirlpool.
    map.add_whirlpool ( this );
}

